
#include <scene/skeletonbone.h>

ceSkeletonBone::ceSkeletonBone(ceAxis axis, float length)
  : _axis (axis)
  , _length (length)
  , _parent (0)
	, _name ("")
{
	CE_OBJECT_CONSTR
  _orientation.SetIdentity();
  _children.clear ();
}

void ceSkeletonBone::SetName (const std::string& name)
{
	_name = name;
}

const std::string& ceSkeletonBone::GetName () const
{
	return _name;
}

void ceSkeletonBone::AddBone(ceSkeletonBone *bone)
{
  if (bone)
    {
      _children.push_back(bone);
      bone->AddRef();
      bone->_parent = this;
    }
}


bool ceSkeletonBone::RemoveBone(ceSkeletonBone *bone, bool recursive)
{
	std::vector<ceSkeletonBone*>::iterator it, eit;
	for (it = _children.begin(), eit = _children.end(); it != eit; ++it)
		{
			ceSkeletonBone* b = *it;
			if (b == bone)
        {
          _children.erase(it);
          b->_parent = 0;
          b->Release();
          return true;
        }
      else if (recursive)
        {
          if (b->RemoveBone(bone, recursive))
            {
              return true;
            }
        }
    }
  return false;
}


ceSkeletonBone* ceSkeletonBone::GetParentBone()
{
  return _parent;
}

const ceSkeletonBone* ceSkeletonBone::GetParentBone() const
{
  return _parent;
}

void ceSkeletonBone::SetAxis(ceAxis axis)
{
  _axis = axis;

  UpdateDir ();
}

ceAxis ceSkeletonBone::GetAxis() const
{
  return _axis;
}

void ceSkeletonBone::SetLength(float length)
{
  _length = length;

  UpdateDir ();
}

float ceSkeletonBone::GetLength() const
{
  return _length;
}

void ceSkeletonBone::SetOrientation(const ceMatrix4f &orientation)
{
  _orientation = orientation;
}

const ceMatrix4f& ceSkeletonBone::GetOrientation() const
{
  return _orientation;
}

const ceMatrix4f& ceSkeletonBone::GetMatrix() const
{
  return _matrix;
}

void ceSkeletonBone::UpdateDir()
{
  _dir = ceVector3f (0.0f, 0.0f, 0.0f);
  switch (_axis)
    {
    case A_X:
      _dir.x = _length;
      break;
    case A_Y:
      _dir.y = _length;
      break;
    case A_Z:
      _dir.z = _length;
      break;
    }
}

void ceSkeletonBone::UpdateBoneTransformation(const ceMatrix4f &base, ceMatrix4f *destMatrices)
{
  _matrix = base * _orientation;

  if (destMatrices)
    {
      destMatrices[_idx] = _matrix;
    }

  ceMatrix4f disp;
  disp.SetTranslation(_dir);

	disp = _matrix * disp;

	for (unsigned i=0, ni=_children.size(); i<ni; ++i)
		{
			_children[i]->UpdateBoneTransformation (disp, destMatrices);
		}
}


